package cn.tianya.irock.core;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.servlet.ServletConfig;

import cn.tianya.irock.cache.ICache;
import cn.tianya.irock.data.model.RolesConfiguration;
import cn.tianya.irock.enums.ApplicationExceptionType;
import cn.tianya.irock.enums.SystemExceptionType;
import cn.tianya.irock.exceptions.ApplicationException;
import cn.tianya.irock.exceptions.SystemException;


public abstract class Configuration {
	// app dir
	protected static final String PATH_RESOURCE = "path.resource";
	protected static final String PATH_CONFIG = "path.config";
	protected static final String PATH_LANGUAGES = "path.languages";
	protected static final String PATH_RES = "path.res";
	protected static final String PATH_DATA = "path.data";
	protected static final String PATH_TEMP = "path.temp";
	protected static final String PATH_UPLOAD = "path.upload";
	protected static final String PATH_APP = "path.app";
	
	protected static final String APP_DOMAIN = "app.domain";
	protected static final String APP_ROOT = "app.root";
	protected static final String APP_LOGINURL = "app.loginurl";
	protected static final String APP_URL = "app.url";
	// app file
	protected static final String FILE_PAGES_SKIN = "file.pages.skin";
	protected static final String FILE_LANGUAGES = "file.languages";
	protected static final String FILE_SITE_URLS = "file.siteurls";
	protected static final String FILE_AUTHORIZATION = "file.authorization";
	protected static final String FILE_SQL_COMMANDS = "file.sqlcommands";
	protected static final String FILE_PAGES = "file.pages";
	protected static final String FILE_FREEMARKER="file.freemarker";
	
	//app setting
	protected static final String ENABLE_AUTH_ACCESS = "app.enable.auth.access";
	protected static final String ENCODING = "app.encoding";
	protected static final String PAGE_EXTENSION = "app.page.extension";
	protected static final String CONNECTION_STRING = "app.connection.string";
	protected static final String DATA_PAGE_SIZE = "app.data.page.size";
	
	protected static final String DEFAULT_CONTAINER_ENCODING = "app.default.container.encoding";
	protected static final String DEFAULT_APP = "app.default.app";
	protected static final String DEFAULT_LANGUAGE = "app.default.language";
	
	// cache key
	public static final String CONFIG_CACHE = "app:config_cache";
	public static final String SITE_URLS_CACHE = "app:site_urls_cache";
	public static final String PAGE_AUTH_CACHE = "app:page_auth_cache";
	public static final String ROLE_CONFIG = "app:role_config";
	
	//
	protected static ServletConfig config;
	
	//
	private static final String pre = "${";
	private static final String post = "}";
	private Properties props;
	private Map<String, String> expProps;
	
	protected Configuration(ServletConfig config) {
		FileInputStream input = null;
		String filePath = null;
		
		Configuration.config = config;
		this.props = new Properties();
		this.expProps = new HashMap<String, String>();
		
		filePath = this.getServerPath() + this.getConfigFile();
		try {
			input = new FileInputStream(filePath);
			this.props.load(input);

		} catch (IOException e) {
			throw new SystemException(SystemExceptionType.FileNotFound, filePath);
		} finally {
			try {input.close();}catch(IOException ex) {}
		}
		
		this.expandVariables();
		HttpRuntime.cache().add(CONFIG_CACHE, this, ICache.MAX_FACTOR);
	}
	
	public abstract SiteUrlsBase getSiteUrls();
	public abstract String getDataDal();
	public abstract String getPostDal();
	public abstract String getUserDal();
	public abstract String getRoleDal();
	public abstract String getSearchDal();
	public abstract String getSectionDal();
	public abstract String getThreadDal();
	public abstract String getSiteDal();
	public abstract String getUrlPatternDal();
	public abstract String getPermissionDal();
	public abstract String getSearchPatternDal();
	public abstract String getAttachmentPatternDal();
	
	public final static Configuration config() {
		Configuration cfg = (Configuration)HttpRuntime.cache().get(CONFIG_CACHE);
		return cfg;
	}
		
	protected void expandVariables() {
		String key = null;
		String value = null;
		for(Map.Entry entry : this.props.entrySet()) {
			key = (String)entry.getKey();
			value = (String)entry.getValue();
			this.expProps.put(key, getExpandVariable(value));
		}
	}
	
	protected String getExpandVariable(String originValue) {
		int sIndex = originValue.indexOf(pre);
		int start = -1;
		int end = -1;
		String variableName = null;
		StringBuilder buffer = new StringBuilder(originValue);
		
		while(sIndex > -1) {
			start = sIndex + pre.length();
			end = buffer.indexOf(post);
			variableName = buffer.substring(start, end);
			end += post.length();
			buffer.replace(sIndex, end, this.props.getProperty(variableName));
			sIndex = buffer.indexOf(pre);
		}
		return buffer.toString();
	}
	
	public void setAppPath(String value) {
		String path = this.getProperty(PATH_APP);
		if (path == null || "".equals(path)) {
			this.expProps.remove(PATH_APP);
		}
		this.expProps.put(PATH_APP, value);
	}
	
	public String getProperty(String key) {
		return this.expProps.get(key);
	}
		
	public String getConfigFile() {
		return "/WEB-INF/config/ApplictaionConfig.properties";
	}
	
	public String getSiteUrlsFile() {
		return this.getProperty(FILE_SITE_URLS);// "/WEB-INF/config/SiteUrls.properties";
	}
	
	public String getAuthorizationFile() {
		return this.getProperty(FILE_AUTHORIZATION);
	}
	
	public String getDefaultApp() {
		return this.getProperty(DEFAULT_APP);//"default";
	}

	public String getServerPath() {
		return config.getServletContext().getRealPath("");
	}
	
	public String getResourcePath() {
		return this.getProperty(PATH_RESOURCE);
	}
	
	public String getConfigPath() {
		return this.getProperty(PATH_CONFIG);
	}
	
	public String getLanguagePath() {
		return this.getProperty(PATH_LANGUAGES);
	}
	
	public String getResPath() {
		return this.getProperty(PATH_RES);
	}
	
	public String getTempPath() {
		return this.getProperty(PATH_TEMP);
	}
	
	public String getUploadPath() {
		return this.getProperty(PATH_UPLOAD);
	}
	
	public String getAppPath() {
		return this.getProperty(PATH_APP);
	}
	
	public String getPagesFile() {
		return this.getProperty(FILE_PAGES);
	}
	
	public String getSqlCommandsFile() {
		return this.getProperty(FILE_SQL_COMMANDS);
	}
	
	public String getPagesSkinFile() {
		return this.getProperty(FILE_PAGES_SKIN);
	}
	
	public String getLanguagesFile() {
		return this.getProperty(FILE_LANGUAGES);
	}
	
	public String getFreemarkerFile() {
		return this.getProperty(FILE_FREEMARKER);
	}
	
	public String getDefaultLanguage() {
		return this.getProperty(DEFAULT_LANGUAGE);
	}
	
	public String getPageExtension() {
		return this.getProperty(PAGE_EXTENSION);
	}
		
	public int getDataPageSize() {
		return Integer.parseInt(this.getProperty(DATA_PAGE_SIZE));
	}
			
	public PageAuthorization getPageAuthorization(int settingsId) {
		String key = PAGE_AUTH_CACHE + "_site_id:" + Integer.toString(settingsId);
		PageAuthorization pa = (PageAuthorization)HttpRuntime.cache().get(key);
		
		if (pa == null) {
			pa = new PageAuthorization(settingsId);
			HttpRuntime.cache().add(key, pa);
		}
		return pa;
	}
	
	public RolesConfiguration getRolesConfiguration() {
		RolesConfiguration roles = (RolesConfiguration)HttpRuntime.cache().get(ROLE_CONFIG);
		if (roles == null) {
			roles = new RolesConfiguration();
			HttpRuntime.cache().add(ROLE_CONFIG, roles);
		}
		return roles;
	}
		
	public String getDomain() {
		return this.getProperty(APP_DOMAIN);
	}
	
	public String getAppRoot() {
		return this.getProperty(APP_ROOT);
	}
	
	public String getAppUrl() {
		return this.getProperty(APP_URL);
	}
	
	public String getAppLoginUrl() {
		return this.getProperty(APP_LOGINURL);
	}
	
	public String getDataPath() {
		return this.getProperty(PATH_DATA);
	}
	
	public boolean enableAuthAccess() {
		return "true".equals(this.getProperty(ENABLE_AUTH_ACCESS));
	}
	
	public String getEncoding() {
		return this.getProperty(ENCODING);
	}
}
